import React, { forwardRef, RefObject, MutableRefObject } from 'react';
import styled from 'styled-components';
import { COLOR_MAP, COLOR_MAP_OUTLINE, DIMENSION_MAP } from './Button.constants';
import {
  IButtonProps,
  IconPosition,
  Dimension,
  Variant
} from './Button.types';
import { StyledButton } from './Button.styled';

/**
 * Стилизованный контейнер для дочерних элементов
 * @param {IChildrenContainer} props - объект с пропсами
 * @param {Dimension} props.dimension - размер контейнера
 * @returns {React.Element} стилизованный компонент контейнера
 */
const ChildrenContainer = styled.div<{ dimension: Dimension }>`
  font-size: ${props =>
    props.dimension ? DIMENSION_MAP[props.dimension].fontSize : DIMENSION_MAP['df'].fontSize};
  letter-spacing: ${props =>
    props.dimension
      ? DIMENSION_MAP[props.dimension].letterSpacing
      : DIMENSION_MAP['df'].letterSpacing};
`;

/**
 * Контейнер для иконки
 * @param {IIconContainer} props - объект с пропсами
 * @param {boolean} props.outline - флаг указывает на то, является ли кнопка контурной
 * @param {Variant} props.variant - вариант цвета иконки
 * @return {React.Element} - компонент контейнера
 */
const IconContainer = styled.div<{variant: Variant, outline: boolean}>`
  width: 0.9375rem;
  height: 0.9375rem;

  path {
    fill: ${props => props.outline ? COLOR_MAP_OUTLINE[props.variant] : COLOR_MAP[props.variant]};
  }

  margin: 0.3125rem;
`;

/**
 * @function Button - компонент кнопки
 * @param {IButtonProps} props - свойства кнопки
 * @param {RefObject<HTMLButtonElement> | MutableRefObject<HTMLButtonElement>} ref - ссылка на элемент кнопки
 * @return {JSX.Element} - элемент кнопки
 */
const Button = forwardRef(
  (
    props: IButtonProps,
    ref: RefObject<HTMLButtonElement> | MutableRefObject<HTMLButtonElement>,
  ) => {
    const {
      children,
      icon,
      iconPosition,
      outline,
      dimension,
      variant,
      round,
      ...nextProps
    } = props;

    /**
+     * Отображает иконку в зависимости от заданной позиции
+     * @param {IconPosition} position - позиция иконки
+     * @return {JSX.Element | null} - элемент с отображаемой иконкой или null, если не применимо
+     */
    const renderIcon = (position: IconPosition) => {
      const showIcon = icon && (iconPosition === position);
      return (
        showIcon && (
          <IconContainer outline={outline} variant={variant}>
            {icon}
          </IconContainer>
        )
      );
    };

    return (
      <StyledButton
        ref={ref}
        dimension={dimension}
        variant={variant}
        round={round}
        outline={outline}
        {...nextProps}
      >
        {renderIcon('left')}
        <ChildrenContainer dimension={dimension}>{children}</ChildrenContainer>
        {renderIcon('right')}
      </StyledButton>
    );
  },
);

Button.defaultProps = {
  variant: 'primary',
  outline: false,
  round: false,
};

Button.displayName = 'Button';

export default Button;
